/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			ResMaterial.d
	Description:	material resource
	Date:			23.11.2007 by Digited
*/
module moonglide.resources.resobjects.hilevel.ResMaterial;

import moonglide.resources.Management;


enum EMatBlendSFactor
{
     one,
     zero,
     dst_color,
     one_min_dst_color,
     src_alpha,
     one_min_src_alpha,
     dst_alpha,
     one_min_dst_alpha,
     src_alpha_sat
}

enum EMatBlendDFactor
{
     zero,
     one,
     src_color,
     one_min_src_color,
     src_alpha,
     one_min_src_alpha,
     dst_alpha,
     one_min_dst_alpha
}

//=============================================================
/// CResMaterial - basic material resource class
//=============================================================
class CResMaterial : IResource
{
	mixin TDynamicProperties;

	protected:
		this( char[] idname )
		{
			vectors4["color"]		= Vector4f(0.7f,0.7f,0.7f,1);
			vectors4["ambient"]		= Vector4f(0.7f,0.7f,0.7f,1);
			vectors4["diffuse"]		= Vector4f(0.2f,0.2f,0.2f,1);
			vectors4["specular"]	= Vector4f(1.0f,1.0f,1.0f,1);
			vectors4["emission"]	= Vector4f(0.0f,0.0f,0.0f,1);
			//
			bools["clamp_use"]		= false;
			floats["clampU_min"]	= 0.0f;
			floats["clampU_max"]	= 1.0f;
			floats["clampV_min"]	= 0.0f;
			floats["clampV_max"]	= 1.0f;
			//
			floats["AlphaPor"]		= 0.5f;

            bools["specialShaderUse"] = false;
			bools["AlphaTest"]		= false;
			bools["Blend"]			= false;
			bools["BackCull"]		= true;
			bools["DepthTest"]		= true;
			bools["Lighting"]		= true;
			bools["OnlyHDR"]        = false;

			bools["DepthRanged"]	= false;
			floats["DepthRangeNear"]= 0.0f;
			floats["DepthRangeFar"]	= 1.0f;

			sourceBlendFactor		= EMatBlendSFactor.one;
			destBlendFactor			= EMatBlendDFactor.zero;

			shader = CResShaderComposite( idname ~ "_shad" );

			ints["DepthCheck"]		= 1;

			ints["shininess"]		= 30;
			ints["DepthMask"]		= 1;


			/// termal object
			bools["term"]           =   false;

			super( idname );
		}

	public:
		Vector4f[char[]]	vectors4;

		CResShaderComposite	shader;
		CResTexture[]		textures;

		EMatBlendSFactor	sourceBlendFactor;
		EMatBlendDFactor	destBlendFactor;

		uint[]				activeTextures;

		invariant()
		{
			static uint texlen = 0;
			texlen = textures.length;

			foreach( index; activeTextures )
				assert( index < texlen );
		}

		//============================================================
		/// NewTexture - adds new texture to this material and return it
		//============================================================
		CResTexture newTexture( char[] id = "", bool load = false )
		{
			char[] tex_id = _id ~ "_tex" ~ intToStr( textures.length );
			CResTexture tex = CResTexture( tex_id );

		    if( id.length )
		    {
		    	auto newData = CResTextureData( id, load );
				tex.data ~= newData;
		    }

			textures ~= tex;
			return tex;
		}

		//============================================================
		/// opCall - main resource getter
		//============================================================
		static CResMaterial opCall( char[] id, bool load = false, char[] errorResource = "" )
		{
			// check for registered ONLY in case we want to load resource
			if( load )
			{
				if( CResManager().Exists( id ))
					debug
					{
						auto tmp = cast(CResMaterial)CResManager().GetResource( id );
						moonAssert( tmp !is null, "casting GetResource to CResMaterial failed", __FILE__, __LINE__ );
						return tmp;
					}
					else
					{
						return cast(CResMaterial)CResManager().GetResource( id );
					}

				auto res = new CResMaterial( id );

				_Load( res, errorResource );
				debug moonAssert( res !is null, "loading CResMaterial returned null", __FILE__, __LINE__ );
				return res;
			}

			// if we do not load, just gen unique name and create new with it.
			CResManager().GenerateUniqueName( id );
			auto res = new CResMaterial( id );

			_New( res );
			return res;
		}

		~this()
		{
			foreach( ref tex; textures )
				if( tex )
				{
					if( tex.isAlive )
						tex.release;

					tex = null;
				}

            if( shader )
			{
				if( shader.isAlive )
					shader.release;

				shader = null;
			}
		}
}
